#include "arpa/inet.h"
#include "ctype.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "sys/socket.h"
#include "sys/types.h"
#include "unistd.h"

#define PORTNUM 15000
#define oops(m) \
  {             \
    perror(m);  \
    exit(1);    \
  }

void sanitize(char *str);

int main(int ac, char *av[]) {
  // step 1: ask kernel for a socket
  int sock_id = socket(PF_INET, SOCK_STREAM, 0);
  if (sock_id == -1) {
    oops("socket");
  }

  // step 2: bind address to socket. Address is server's address
  struct sockaddr_in my_addr;
  memset(&my_addr, 0, sizeof(my_addr));
  my_addr.sin_family = AF_INET;
  my_addr.sin_port = htons(PORTNUM);
  my_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
  if (bind(sock_id, (struct sockaddr *)&my_addr, sizeof(my_addr)) != 0) {
    oops("bind");
  }

  // step 3: listen
  if (listen(sock_id, 1) != 0) {
    oops("listen");
  }

  // step 4: accept & handle request
  while (1) {
    int sock_fd = accept(sock_id, NULL, NULL);
    if (sock_fd == -1) {
      oops("accept");
    }

    FILE *sock_fpi, *sock_fpo;
    if ((sock_fpi = fdopen(sock_fd, "r")) == NULL) {
      oops("fdopen reading");
    }
    char dirname[BUFSIZ];
    char command[BUFSIZ + 4];
    if (fgets(dirname, BUFSIZ, sock_fpi) == NULL) {
      oops("reading");
    }
    sanitize(dirname);

    if ((sock_fpo = fdopen(sock_fd, "w")) == NULL) {
      oops("fdopen writing");
    }

    sprintf(command, "ls %s", dirname);
    FILE *fp = popen(command, "r");
    if (fp == NULL) {
      oops("popen");
    }

    char c;
    while ((c = getc(fp)) != EOF) {
      putc(c, sock_fpo);
    }

    pclose(fp);
    fclose(sock_fpo);
    fclose(sock_fpi);
  }

  return 0;
}

void sanitize(char *str) {
  char *src, *dest;
  for (src = dest = str; *src; src++) {
    if (*src == '/' || isalnum(*src)) {
      *dest++ = *src;
    }
  }
  *dest = '\0';
}